package com.imooc.security.server.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.web.firewall.DefaultHttpFirewall;
import org.springframework.security.web.firewall.HttpFirewall;
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
//import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;

import javax.sql.DataSource;

/**
 * @ClassName OAuth2AuthServerConfig
 * @Description TODO 认证服务器
 * @Author wushaopei
 * @Date 2021/5/2 21:44
 * @Version 1.0
 */
@EnableJdbcHttpSession
@Configuration  //这是一个配置类
@EnableAuthorizationServer  // 当前应用是一个认证服务器
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter  {


    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Bean
    public TokenStore tokenStore(){
        return new JdbcTokenStore(dataSource);
    }

    //允许多请求地址多加斜杠  比如 /msg/list   //msg/list
    @Bean
    public HttpFirewall httpFirewall() {
        return new DefaultHttpFirewall();
    }

    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("123456"));
    }

    /***
     * @Description 配置客户端应用的信息，让认证服务器知道有哪些客户端应用来申请令牌。
     * @param clients 客户端的详情服务的配置
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
//        clients.inMemory()  //添加客户端应用,配置在内存里，后面修改为数据库里
//                .withClient("orderApp")// 指定client的id，应用的用户名，这里添加的是客户端应用
//                .secret(passwordEncoder.encode("123456")) // 应用的密码
//                .scopes("read", "write") // 应用的权限
//                .accessTokenValiditySeconds(3600) // 令牌的有效期，单位为秒s
//                .resourceIds("order-server")  // 资源服务器的id。指：我发给orderApp的token可以访问哪些资源服务器
//                .authorizedGrantTypes("password") // 授权方式，指可以用哪种方式去实现
//                .and()
//                .withClient("orderService")// 指定client的id，应用的用户名，这里添加的是订单服务。微服务中，订单服务应该具备访问其他服务的权利，同样需要获取令牌
//                .secret(passwordEncoder.encode("123456")) // 应用的密码
//                .scopes("read") // 应用的权限
//                .accessTokenValiditySeconds(3600) // 令牌的有效期，单位为秒s
//                .resourceIds("order-server")  // 资源服务器的id。指：我发给orderApp的token可以访问哪些资源服务器
//                .authorizedGrantTypes("password") // 授权方式，指可以用哪种方式去实现
//                .and()
//                .withClient("gateway")// 指定client的id，应用的用户名，这里添加的是订单服务。微服务中，订单服务应该具备访问其他服务的权利，同样需要获取令牌
//                .secret(passwordEncoder.encode("123456")) // 应用的密码
//                .scopes("read", "write") // 应用的权限
//                .accessTokenValiditySeconds(3600) // 令牌的有效期，单位为秒s
//                .resourceIds("order-server")  // 资源服务器的id。指：我发给orderApp的token可以访问哪些资源服务器
//                .authorizedGrantTypes("password"); // 授权方式，指可以用哪种方式去实现
    }


    /**
     * @Description TODO 配置用戶信息
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 传给他一个authenticationManager用来校验传过来的用户信息是不是合法的,注进来一个，自己实现
//        endpoints.authenticationManager(authenticationManager);
        endpoints
                .userDetailsService(userDetailsService) // 这种才是支持refresh_token刷新令牌模式的
                .tokenStore(tokenStore())
                .authenticationManager(authenticationManager); // 这里只支持前四种授权类型
    }

    /**
     * @Description TODO 配置资源服务器过来验token的规则
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        /**
         * 过来验令牌有效性的请求，不是谁都能验的，必须要是经过身份认证的。
         * 所谓身份认证就是，必须携带clientId，clientSecret，否则随便一请求过来验token是不验的
         */
        security.checkTokenAccess("isAuthenticated()");
    }

}
